home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / sbin / ndiswrapper-1.9 < prev    next >
Encoding:
Text File  |  2007-03-29  |  22.8 KB  |  879 lines

  1. #!/usr/bin/perl
  2.  
  3. #/*
  4. #*  Copyright (C) 2005-2006 Pontus Fuchs, Giridhar Pemmasani
  5. #*
  6. #*
  7. #*  This program is free software; you can redistribute it and/or modify
  8. #*  it under the terms of the GNU General Public License as published by
  9. #*  the Free Software Foundation; either version 2 of the License, or
  10. #*  (at your option) any later version.
  11. #*
  12. #*  This program is distributed in the hope that it will be useful,
  13. #*  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. #*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. #*  GNU General Public License for more details.
  16. #*
  17. #*/
  18.  
  19. use strict;
  20. use Fcntl ':mode';
  21. use File::Basename;
  22. use File::Copy;
  23. use File::Path;
  24. use Cwd;
  25.  
  26. $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}";
  27.  
  28. my $WRAP_PCI_BUS = 5;
  29. my $WRAP_PCMCIA_BUS = 8;
  30. my $WRAP_USB_BUS = 15;
  31.  
  32. my %sections;
  33. my %parsed_sections;
  34. my $confdir = "/etc/ndiswrapper";
  35. my $src_dir;
  36. my $driver_name;
  37.  
  38. my $re_dev_id = "([[:xdigit:]]{4})";
  39. my $re_sub_dev_conf = "$re_dev_id:$re_dev_id:$re_dev_id:$re_dev_id" .
  40.   "\.([[:xdigit:]]+)\.conf";
  41. my $re_dev_conf = "$re_dev_id:$re_dev_id\.([[:xdigit:]]+)\.conf";
  42.  
  43. # fixup list for parameters.
  44. my %param_fixlist = ("EnableRadio|0" => "1",
  45.              "IBSSGMode|0" => "2",
  46.              "PrivacyMode|0" => "2",
  47.              "MapRegisters|256" => "64",
  48.              "AdhocGMode|1" => "0");
  49.  
  50. if (@ARGV < 1) {
  51.     usage();
  52.     exit(1);
  53. }
  54.  
  55. my $modconf;
  56. if (`uname -r` =~ /(\d+)\.(\d+)\.(\d+)/) {
  57.     if ($2 > 4) {
  58.     if (-d "/etc/modprobe.d") {
  59.         $modconf = "/etc/modprobe.d/ndiswrapper"
  60.     } else {
  61.         $modconf = "/etc/modprobe.conf"
  62.     }
  63.     } else {
  64.     if (-d "/etc/modutils") {
  65.         $modconf = "/etc/modutils/ndiswrapper";
  66.     } else {
  67.         $modconf = "/etc/modules.conf";
  68.     }
  69.     }
  70. }
  71.  
  72. my $res;
  73. my $dbg_file;
  74.  
  75. $dbg_file = ">/dev/null";
  76.  
  77. # "-D" is for development/debugging only
  78. if ($ARGV[0] eq "-D") {
  79.     $dbg_file = ">/tmp/ndiswrapper.dbg";
  80.     $confdir = "/tmp/ndiswrapper";
  81.     shift;
  82. }
  83.  
  84. open(DBG, $dbg_file) or die "couldn't open $dbg_file: $!";
  85.  
  86. if ($ARGV[0] eq "-i" and @ARGV == 2) {
  87.     $res = install($ARGV[1]);
  88. } elsif (($ARGV[0] eq "-a" or $ARGV[0] eq "-d") and @ARGV == 3) {
  89.     $res = device_driver_alias($ARGV[1], $ARGV[2]);
  90. } elsif (($ARGV[0] eq "-e" or $ARGV[0] eq "-r") and @ARGV == 2) {
  91.     $res = remove_driver($ARGV[1]);
  92. } elsif ($ARGV[0] eq "-l" and @ARGV == 1) {
  93.     $res = list_drivers();
  94. } elsif ($ARGV[0] eq "-m" and @ARGV == 1) {
  95.     $res = add_module_alias();
  96. } elsif ($ARGV[0] eq "-v" and @ARGV == 1) {
  97.     printf "utils "; system("loadndisdriver -v");
  98.     printf "driver ";
  99.     system("modinfo ndiswrapper | grep -E '^version|^vermagic'");
  100.     $res = 0;
  101. } elsif ($ARGV[0] eq "-ma" and @ARGV == 1) {
  102.     $res = generate_module_device_map(0);
  103. } elsif ($ARGV[0] eq "-mi" and @ARGV == 1) {
  104.     $res = generate_module_device_map(1);
  105. } else {
  106.     usage();
  107. }
  108. close(DBG);
  109. exit($res);
  110.  
  111. sub usage() {
  112.     print "install/manage Windows drivers for ndiswrapper\n\n" .
  113.         "usage: ndiswrapper OPTION\n" .
  114.     "-i inffile       install driver described by 'inffile'\n" .
  115.     "-a devid driver  use installed 'driver' for 'devid'\n" .
  116.     "-r driver        remove 'driver'\n" .
  117.     "-l               list installed drivers\n" .
  118.     "-m               write configuration for modprobe\n" .
  119.     "-ma              write module alias configuration for all devices\n" .
  120.     "-mi              write module install configuration for all devices\n" .
  121.     "-v               report version information\n\n" .
  122.     "where 'devid' is either PCIID or USBID of the form XXXX:XXXX,\n" .
  123.       "as reported by 'lspci -n' or 'lsusb' for the card\n";
  124. }
  125.  
  126. sub remove_driver {
  127.     my $driver = shift;
  128.     if (!rmtree("$confdir/$driver", 0, 1)) {
  129.     warn "couldn't delete $confdir/$driver: $!\n";
  130.     }
  131.     return 0;
  132. }
  133.  
  134. sub install {
  135.     my $inf = shift;
  136.     chomp($inf);
  137.     $src_dir = dirname($inf);
  138.     $driver_name = lc(basename($inf));
  139.     $driver_name =~ s/\.inf//;
  140.  
  141.     if (! -d $confdir) {
  142.     mkdir($confdir) or die "couldn't create $confdir: $!";
  143.     }
  144.     (-d "$confdir/$driver_name") and
  145.       die "driver $driver_name is already installed\n";
  146.     mkdir("$confdir/$driver_name") or
  147.       die "couldn't create $confdir/$driver_name: $!";
  148.     print "installing $driver_name ...\n";
  149.     read_sections($inf);
  150.     parse_section("Strings");
  151.     parse_section("Version");
  152.     parse_mfr();
  153.     copy_file(basename($inf));
  154.     create_fuzzy_conf($driver_name);
  155.     return 0;
  156. }
  157.  
  158. # return lines in section
  159. sub get_section {
  160.     my $name = shift;
  161.     foreach my $key (keys %sections) {
  162.     if (lc($key) eq lc($name)) {
  163.         printf DBG "section: $key\n";
  164.         return \@{$sections{$key}};
  165.     }
  166.     }
  167.     printf DBG "couldn't find section \"$name\"\n";
  168.     return 0;
  169. }
  170.  
  171. # load inf and split into different sections.
  172. sub read_sections {
  173.     my $filename = shift;
  174.     open(INF, $filename) or die "couldn't open $filename: $!";
  175.  
  176.     my $name = "none";
  177.     @{$sections{$name}} = ();
  178.     while (my $line = <INF>) {
  179.     # convert from unicode
  180.     $line =~ s/\xff\xfe//;
  181.     $line =~ s/\0//g;
  182.  
  183.     chomp($line);
  184.     $line = trim($line);
  185.     next if ($line =~ /^$/);
  186.     if ($line =~ /^\[(.+)\]/) {
  187.         $name = $1;
  188.         @{$sections{$name}} = ();
  189.     } else {
  190.         push(@{$sections{$name}}, $line);
  191.     }
  192.     }
  193.     close(INF);
  194.     foreach $name (keys %sections) {
  195.     printf DBG "section: %s\n", $name;
  196.     foreach my $line (@{$sections{$name}}) {
  197.         printf DBG "%s: %s\n", $name, $line;
  198.     }
  199.     }
  200. }
  201.  
  202. sub parse_section {
  203.     my $name = shift;
  204.     my $lines = get_section($name);
  205.     if (!$lines) {
  206.     return;
  207.     }
  208.     $parsed_sections{$name} = ();
  209.     foreach my $line (@{$lines}) {
  210.     (my $key, my $val) = parse_key_value($line);
  211.     if ($key) {
  212.         $val = strip_quotes($val);
  213.         $parsed_sections{$name}->{$key} = $val;
  214.         printf DBG "$name: %s = %s\n", $key, $val;
  215.     }
  216.     }
  217. }
  218.  
  219. sub parse_mfr() {
  220.     my $lines = get_section("Manufacturer");
  221.     $lines or die "couldn't get manufacturer section - " .
  222.       "installation may be incomplete\n";
  223.     foreach  my $line (@{$lines}) {
  224.     (my $strkey, my $val) = parse_key_value($line);
  225.     if ($strkey) {
  226.         (my $models, my @targets) = split(",", $val);
  227.         if ($models) {
  228.         printf DBG "mfr: %s, %s\n", $line, $models;
  229.         parse_models($models);
  230.         }
  231.     }
  232.     }
  233. }
  234.  
  235. sub parse_models {
  236.     my $models = shift;
  237.     my $lines = get_target_os_section($models);
  238.     if (!$lines) {
  239.     warn "couldn't find models section \"$models\" -\n" .
  240.       "installation may be incomplete\n";
  241.     return -1;
  242.     }
  243.     foreach my $line (@{$lines}) {
  244.     $line = del_comment($line);
  245.     next if (length($line) eq 0);
  246.     (my $dev_desc, my $val) = parse_key_value($line);
  247.     my @fields = split(",", $val);
  248.     if (@fields le 1) {
  249.         printf "couldn't find install directive: %s\n", $line;
  250.         next;
  251.     }
  252.     my $install_section = trim($fields[0]);
  253.     my $hwid = trim($fields[1]);
  254.     if ($hwid =~ /^%.+%$/) {
  255.         $hwid = get_string_value($hwid);
  256.     }
  257.     # TODO: deal with compatible IDs as hwid?
  258.     (my $bus_type, my $vendor, my $device, my $subvendor, my $subdevice) =
  259.       parse_hwid($hwid);
  260.     printf DBG "models: %s, %s\n", $install_section, $hwid, $vendor;
  261.     next if (!$vendor);
  262.     parse_install($install_section, $bus_type, $vendor, $device,
  263.               $subvendor, $subdevice);
  264.     }
  265. }
  266.  
  267. sub parse_install {
  268.     (my $secn, my $bus_type, my $vendor, my $device,
  269.      my $subvendor, my $subdevice) = @_;
  270.     my $lines = get_target_os_section($secn);
  271.     if (!$lines) {
  272.     warn "couldn't find install section \"$secn\" -\n" .
  273.       "installation may be incomplete\n";
  274.     return -1;
  275.     }
  276.  
  277.     my $filename = "$vendor:$device";
  278.     if ($subvendor) {
  279.     $filename .= ":$subvendor:$subdevice"
  280.     }
  281.     $filename .= sprintf(".%X.conf", $bus_type);
  282.  
  283.     my @addregs;
  284.     my @copyfiles;
  285.     foreach my $line (@{$lines}) {
  286.     $line =~ s/^;\s*//;
  287.     $line = trim(del_comment($line));
  288.     (my $key, my $val) = parse_key_value($line);
  289.     my @array;
  290.     if ($key) {
  291.         if (lc($key) eq "addreg") {
  292.         @array = split(",", $val);
  293.         foreach my $reg (@array) {
  294.             push @addregs, trim($reg);
  295.         }
  296.         } elsif (lc($key) eq "copyfiles") {
  297.         printf DBG "copyfiles: %s\n", $val;
  298.         @array = split(",", $val);
  299.         foreach my $copy_file (@array) {
  300.             my @copy_sec = split(",", $copy_file);
  301.             foreach my $file (@copy_sec) {
  302.             push @copyfiles, trim($file);
  303.             }
  304.         }
  305.         } elsif (lc($key) eq "bustype") {
  306.         printf DBG "bustype: %s\n", $val;
  307.         $bus_type = $val;
  308.         }
  309.     }
  310.     }
  311.  
  312.     open(CONF, ">$confdir/$driver_name/$filename") or
  313.       die "couldn't create file $filename: $!";
  314.  
  315.     my $version = get_section_value("Version", "DriverVer");
  316.     my $provider = get_section_value("Version", "Provider");
  317.     my $classguid = get_section_value("Version", "ClassGUID");
  318.     my $providerstring = trim(strip_quotes(get_string_value(trim($provider))));
  319.     $classguid =~ s/^\s*{//;
  320.     $classguid =~ s/}\s*$//;
  321.  
  322.     printf CONF "NdisVersion|0x50001\n";
  323.     printf CONF "Environment|1\n";
  324.     printf CONF "class_guid|%s\n", $classguid;
  325.     printf CONF "mac_address|XX:XX:XX:XX:XX:XX\n";
  326.     printf CONF "driver_version|%s,%s\n", $providerstring, $version;
  327.     printf CONF "BusType|%s\n", $bus_type;
  328.     printf CONF "SlotNumber|01\n";
  329.     printf CONF "\n";
  330.     close(CONF);
  331.  
  332.     open(CONF, "|sort|uniq >>$confdir/$driver_name/$filename") or
  333.       die "couldn't create file $confdir/$driver_name/$filename: $!";
  334.  
  335.     foreach my $reg (@addregs) {
  336.     parse_registry($reg);
  337.     }
  338.     foreach my $file (@copyfiles) {
  339.     parse_copy_file($file);
  340.     }
  341.     # RTL8185L driver crashes if DriverDesc setting is not found
  342.     if ($vendor == "10EC" && $device == "8185") {
  343.     printf CONF "DriverDesc|Realtek RTL8185 54M Wireless LAN Network Adapter\n";
  344.     }
  345.     close(CONF);
  346. }
  347.  
  348. sub parse_registry {
  349.     my $reg = shift;
  350.     my $conf = shift;
  351.     my $lines = get_section($reg);
  352.     if (!$lines) {
  353.     warn "couldn't find section \"$reg\" -\n" .
  354.       "installation may be incomplete\n";
  355.     return -1;
  356.     }
  357.  
  358.     foreach my $line (@{$lines}) {
  359.     $line = del_comment($line);
  360.     my @fields = split(",", $line);
  361.     next if (@fields lt 4);
  362.     my $value;
  363.     my $param = trim($fields[1]);
  364.     if ($param =~ /^ndi\\/i) {
  365.         if ($param =~ /^ndi\\params\\(.+)/i) {
  366.         $param = strip_quotes(trim($1));
  367.         $param =~ s/\\.*$//;
  368.         next if (lc(trim($fields[2])) ne "default");
  369.         $value = strip_quotes(trim($fields[4]));
  370.         } else {
  371.         printf DBG "ignoring parameter $line\n";
  372.         next;
  373.         }
  374.     } else {
  375.         $param = strip_quotes(trim($fields[2]));
  376.         next if (length($param) eq 0);
  377.         $value = strip_quotes(trim($fields[4]));
  378.     }
  379.     $value = get_string_value($value);
  380.     if (length($param) gt 0) {
  381.         if ($param_fixlist{"$param|$value"}) {
  382.         my $orig_value = $value;
  383.         $value = $param_fixlist{"$param|$value"};
  384.         printf "forcing parameter $param from $orig_value to $value\n";
  385.         }
  386.         printf CONF "%s|%s\n", $param, $value;
  387.     }
  388.     }
  389. }
  390.  
  391. sub parse_copy_file {
  392.     my $copy_name = shift;
  393.  
  394.     if ($copy_name =~ /^\@/) {
  395.     $copy_name =~ s/^\@//;
  396.     return copy_file($copy_name);
  397.     }
  398.  
  399.     my $lines = get_section($copy_name);
  400.     if (!$lines) {
  401.     warn "couldn't find section \"$copy_name\" -\n" .
  402.       "installation may be incomplete\n";
  403.     return -1;
  404.     }
  405.     foreach my $line (@{$lines}) {
  406.     $line = trim($line);
  407.  
  408.     my @files = split(",", $line);
  409.     if (@files == 0) {
  410.         printf DBG "copyfiles section $copy_name has no files\n";
  411.         return -1;
  412.     }
  413.     my $file;
  414.     if (@files > 1 and length($files[1]) > 0) {
  415.         $file = $files[1];
  416.     } else {
  417.         $file = $files[0];
  418.     }
  419.     printf DBG "file: '%s'\n", $file;
  420.     # some inf files have file names commented out; get file names from them
  421.     $file =~ s/^\s*;//;
  422.     # remove (trailing) comment
  423.     $file = del_comment($file);
  424.     $file = trim($file);
  425.     if (length($file) > 0) {
  426.         if (valid_copy_file_name($file)) {
  427.         copy_file($file);
  428.         } else {
  429.         printf DBG "invalid file '%s' ignored\n", $file;
  430.         }
  431.     }
  432.     }
  433.     return 0;
  434. }
  435.  
  436. sub parse_hwid {
  437.     my $hwid = uc(shift);
  438.     if ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)&SUBSYS_(\w{4})(\S{4})/) {
  439.     return ($WRAP_PCI_BUS, $2, $3, $4, $5);
  440.     } elsif ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)/) {
  441.     return ($WRAP_PCI_BUS, $2, $3, 0, 0);
  442.     } elsif ($hwid =~ /(USB\\)?VID_(\w+)&PID_(\w+)/) {
  443.     return ($WRAP_USB_BUS, $2, $3, 0, 0);
  444.     } else {
  445.     return 0;
  446.     }
  447. }
  448.  
  449. sub parse_key_value {
  450.     my $line = shift;
  451.  
  452.     $line = del_comment($line);
  453.     if ($line =~ /([^=]+)=(.+)/) {
  454.     return (trim($1), trim($2));
  455.     } else {
  456.     return 0;
  457.     }
  458. }
  459.  
  460. sub get_target_os_section {
  461.     my $secn = shift;
  462.     my $arch = `uname -m`;
  463.     chomp($arch);
  464.     if ($arch =~ /64$/) {
  465.     $arch = "AMD64";
  466.     } else {
  467.     $arch = "X86";
  468.     }
  469.     chomp($secn);
  470.     $secn =~ s/^\s*"\s*//;
  471.     $secn =~ s/\s*"\s*$//;
  472.     printf DBG "secn: \"%s\"\n", $secn;
  473.     $secn =~ s/\.NT($arch)?(\.5\.1)?$//;
  474.     printf DBG "secn: \"%s\"\n", $secn;
  475.  
  476.     my $lines = get_section($secn . ".NT" . $arch . ".5.1");
  477.     return $lines if ($lines);
  478.  
  479.     $lines = get_section($secn . ".NT" . $arch);
  480.     return $lines if ($lines);
  481.  
  482.     $lines = get_section($secn . ".NT.5.1");
  483.     return $lines if ($lines);
  484.  
  485.     $lines = get_section($secn . ".NT");
  486.     return $lines if ($lines);
  487.  
  488.     $lines = get_section($secn);
  489.     return $lines if ($lines);
  490.  
  491.     printf DBG "couldn't find section \"$secn\" for \"$arch\"\n";
  492.     return 0;
  493. }
  494.  
  495. sub get_section_value {
  496.     (my $secn, my $name) = @_;
  497.     return $parsed_sections{$secn}->{$name};
  498. }
  499.  
  500. sub get_string_value {
  501.     my $key = shift;
  502.     if ($key =~ /%(.+)%/) {
  503.     $key = $1;
  504.     return get_section_value("Strings", $key);
  505.     } else {
  506.     return $key;
  507.     }
  508. }
  509.  
  510. sub copy_file {
  511.     my $file = shift;
  512.  
  513.     $file = trim(del_comment($file));
  514.     my $real_file = get_file($file);
  515.     if (length($real_file) gt 0) {
  516.     $file = lc($real_file);
  517.     copy("$src_dir/$real_file", "$confdir/$driver_name/$file") or
  518.       warn "couldn't copy \"$src_dir/$real_file\" to " .
  519.         "\"$confdir/$driver_name\": $! -\n" .
  520.           "installation may be incomplete\n";
  521.     chmod(0644, "$confdir/$driver_name/$file");
  522.     } else {
  523.     warn "couldn't find \"$file\" in \"$src_dir\"; make sure " .
  524.       "all driver files, including .inf, .sys (and .bin, if any) " .
  525.         "are in \"$src_dir\" -\n" .
  526.           "installation may be incomplete\n";
  527.     }
  528. }
  529.  
  530. # for conf files with subvendor and subdevice, create conf files with just
  531. # vendor and device
  532. sub create_fuzzy_conf {
  533.     my $driver = shift;
  534.     my $cwd = cwd();
  535.     chdir("$confdir/$driver") or die "couldn't chdir to $confdir/$driver: $!";
  536.     open(LS, "ls -1 . |") or die "couldn't open $confdir/$driver: $!";
  537.     while (my $file = <LS>) {
  538.     chomp($file);
  539.     if ($file =~ /^(.{4}):(.{4}):(.{4}):(.{4})\.([^.]+)\.conf$/) {
  540.         my $fuzzy_file = "$1:$2.$5.conf";
  541.         printf DBG "file: $file, fuzzy file: $fuzzy_file\n";
  542.         if (! -e "$confdir/$driver/$fuzzy_file") {
  543.         symlink("$file", "$fuzzy_file") or
  544.           warn "couldn't link $confdir/$driver/$file " .
  545.             "to $confdir/$driver/$fuzzy_file: $!\n";
  546.         }
  547.     }
  548.     }
  549.     close(LS);
  550.     chdir($cwd) or warn "couldn't chdir to $cwd: $!";
  551.     return 0;
  552. }
  553.  
  554. # find a file in a case-insensitive way.
  555. sub get_file {
  556.     my $file = lc(shift);
  557.     if (opendir(DIR, "$src_dir")) {
  558.     my @allfiles = readdir(DIR);
  559.     foreach my $real_file (@allfiles) {
  560.         if (lc($real_file) eq $file) {
  561.         closedir(DIR);
  562.         return $real_file;
  563.         }
  564.     }
  565.     closedir(DIR);
  566.     } else {
  567.     warn "couldn't open \"$src_dir\": $! - installation may be incomplete\n";
  568.     }
  569.     return "";
  570. }
  571.  
  572. sub strip_quotes {
  573.     my $s = shift;
  574.     $s =~ s/"(.*)"/$1/;
  575.     return $s;
  576. }
  577.  
  578. sub del_comment {
  579.     my $s = shift;
  580.     $s =~ s/;.*//;
  581.     return $s;
  582. }
  583.  
  584. # remove whitsepace at front and end.
  585. sub trim {
  586.     my $s = shift;
  587.     $s =~ s/^\s*//;
  588.     $s =~ s/\s*$//;
  589.     return $s;
  590. }
  591.  
  592. sub valid_copy_file_name {
  593.     my $file = shift;
  594.     printf DBG "file name: %s\n", $file;
  595.     # as of now, copy file name extensions known: .sys, .bin, .out
  596.     return 1 if (lc($file) =~ /^[a-z0-9_]*\.((sys)|(bin)|(out))$/);
  597.     return 0;
  598. }
  599.  
  600. sub device_driver_alias {
  601.     my ($devid, $driver) = @_;
  602.     my $done = 0;
  603.  
  604.     $devid = uc($devid);
  605.     if (!($devid =~ /^$re_dev_id:$re_dev_id$/)) {
  606.     printf "'$devid' is not a valid device ID\n";
  607.     return 1;
  608.     }
  609.     open(LS, "ls -1 $confdir/$driver/ |") or
  610.       die "couldn't open $confdir/$driver: $!";
  611.     while (my $f = <LS>) {
  612.     chomp($f);
  613.     if ($f =~ /\.([[:xdigit:]]+)\.conf$/) {
  614.         if (symlink("$f", "$confdir/$driver/$devid.$1.conf")) {
  615.         printf "driver '$driver' is used for '$devid'\n";
  616.         $done = 1;
  617.         last;
  618.         } else {
  619.         warn "couldn't create symlink for \"$f\": $! -\n" .
  620.           "installation may be incomplete\n";
  621.         }
  622.     }
  623.     }
  624.     close(LS);
  625.     if ($done == 0) {
  626.     printf "driver '$driver' is not installed (properly)!\n";
  627.     return 1;
  628.     }
  629.     return 0;
  630. }
  631.  
  632. sub generate_module_device_map {
  633.     my $mode = shift;
  634.     my $vendor, my $device, my $subvendor, my $subdevice, my $bustype, my $busid;
  635.  
  636.     my $device_map;
  637.     if (-d "/etc/modprobe.d") {
  638.     $device_map = "/etc/modprobe.d/ndiswrapper";
  639.     } elsif (-d "/etc/modules.d") {
  640.     $device_map = "/etc/modules.d/ndiswrapper";
  641.     } else {
  642.     $device_map = "/etc/ndiswrapper/ndiswrapper";
  643.     }
  644.  
  645.     open(CONF, "| sort >$device_map") or
  646.       die "couldn't create modules alias file $device_map: $!";
  647.     open(LS, "ls -1 $confdir|") or
  648.       die "couldn't open $confdir: $!";
  649.     while (my $driver = <LS>) {
  650.     chomp($driver);
  651.     my $stat = (stat("$confdir/$driver"))[2];
  652.     if (S_ISDIR($stat)) {
  653.         open(LS2, "ls -1 $confdir/$driver/ |") or
  654.           die "couldn't open $confdir/$driver: $!";
  655.         while (my $file = <LS2>) {
  656.         chomp ($file);
  657.         if ($file =~ /.conf$/) {
  658.             if ($file =~ /^(.{4}):(.{4}):(.{4}):(.{4})\.([^.]+)\.conf$/) {
  659.             ($vendor, $device, $subvendor, $subdevice, $busid) =
  660.               (uc($1), uc($2), "0000$3", "0000$4", hex($5));
  661.             } elsif ($file =~ /(.{4}):(.{4})\.([^.]+)\.conf$/) {
  662.             ($vendor, $device, $subvendor, $subdevice, $busid) =
  663.               (uc($1), uc($2), "*", "*", hex($3));
  664.             }
  665.             my $devstring;
  666.             if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
  667.             $devstring = sprintf("usb:v%sp%sd*dc*dsc*dp*ic*isc*ip*",
  668.                          $vendor, $device);
  669.             } elsif ($busid eq $WRAP_PCI_BUS) {
  670.             $devstring = sprintf("pci:v0000%sd0000%ssv%ssd%sbc*sc*i*",
  671.                          $vendor, $device, $subvendor,
  672.                          $subdevice);
  673.             } else {
  674.             warn "wrong bustype ($busid) for " .
  675.               "configuration file $file - ignoring it\n";
  676.             next;
  677.             }
  678.             if ($mode == 0) {
  679.             printf CONF "alias %s ndiswrapper\n", $devstring;
  680.             } else {
  681.             printf CONF "install %s /sbin/modprobe ndiswrapper\n",
  682.               $devstring;
  683.             }
  684.         }
  685.         }
  686.         close(LS2);
  687.     }
  688.     }
  689.     close(LS);
  690.     close(CONF);
  691.  
  692.     printf "module configuration information is stored in $device_map\n";
  693.     return 0;
  694. }
  695.  
  696. sub list_drivers {
  697.     my $cards = get_cards();
  698.  
  699.     open(LS, "ls -1 $confdir|") or die "couldn't open $confdir: $!";
  700.     while (my $driver = <LS>) {
  701.     chomp($driver);
  702.     if (-e "$confdir/$driver") {
  703.         printf "%s : %s\n", $driver, install_status($cards, $driver);
  704.     }
  705.     }
  706.     close(LS);
  707.     return 0;
  708. }
  709.  
  710. sub add_module_alias {
  711.     my $alias = 0;
  712.  
  713.     open(MODPROBE, "modprobe -c|") or die "couldn't run modprobe: $!";
  714.     while (my $line = <MODPROBE>) {
  715.     if ($line =~ /^alias\s.+\sndiswrapper/) {
  716.         printf "module configuration already contains alias directive\n\n";
  717.         $alias = 1;
  718.     } elsif ($line =~ /^install\s.*ndiswrapper/) {
  719.         warn "module configuration contains directive $line;" .
  720.           "you should delete that";
  721.     } elsif ($line =~ /^post-install\s+ndiswrapper/) {
  722.         warn "module configuration contains directive $line;" .
  723.           "you should delete that";
  724.     }
  725.     }
  726.     close(MODPROBE);
  727.  
  728.     if ($alias) {
  729.     return 0;
  730.     }
  731.  
  732.     printf "adding \"alias wlan0 ndiswrapper\" to $modconf ...\n";
  733.     system("echo \"alias wlan0 ndiswrapper\" >>$modconf") == 0 or
  734.       die "couldn't add module alias: $!";
  735.     if (-x "/sbin/update-modules") {
  736.     system("/sbin/update-modules");
  737.     }
  738.     return 0;
  739. }
  740.  
  741. sub get_cards {
  742. #01:00.0 Class 0300: 1002:4c66 (rev 01)
  743. #        Subsystem: 1043:1732
  744.     my @cards = ();
  745.     if (open(LSPCI, "lspci -vn|")) {
  746.     my $card;
  747.     while (my $line = <LSPCI>) {
  748.         if ($line =~ /^[0-9a-f]+.+\s$re_dev_id:$re_dev_id/) {
  749.         $card = {vendor => uc($1), device => uc($2)};
  750.         printf DBG "card: %s, %s\n", $1, $2;
  751.         } elsif ($line =~ /.+Subsystem:\s$re_dev_id:$re_dev_id/) {
  752.         $card->{subvendor} = uc($1);
  753.         $card->{subdevice} = uc($2);
  754.         printf DBG "sub: %s, %s\n", $1, $2;
  755.         push(@cards, $card);
  756.         }
  757.     }
  758.     close(LSPCI);
  759.     }
  760.  
  761.     if (open(LSUSB, "lsusb |")) {
  762.     my $card;
  763.     while (my $line = <LSUSB>) {
  764.         if ($line =~ /.+: ID\s$re_dev_id:$re_dev_id/) {
  765.         $card = {vendor => uc($1), device => uc($2)};
  766.         push(@cards, $card);
  767.         }
  768.     }
  769.     close(LSUSB);
  770.     }
  771.     return \@cards;
  772. }
  773.  
  774. sub install_status {
  775.     my ($cards, $driver) = @_;
  776.  
  777.     if (!$cards or !$driver) {
  778.     return;
  779.     }
  780.  
  781.     my $sys, my $conf, my $inf;
  782.     my $vendor, my $device, my $subvendor, my $subdevice, my $busid, my $ret;
  783.  
  784.     $sys = $conf = $inf = 0;
  785.     open(LS2, "ls -1 $confdir/$driver|") or
  786.       die "couldn't open $confdir/$driver: $!";
  787.     while (my $file = <LS2>) {
  788.     chomp($file);
  789.     if ($file =~ /\.sys$/) {
  790.         $sys = 1;
  791.     } elsif ($file =~ /\.inf$/) {
  792.         $inf = 1;
  793.     } elsif ($file =~ /^$re_sub_dev_conf$/) {
  794.         $busid = hex($5);
  795.         $conf = 1 if ($busid eq $WRAP_PCI_BUS);
  796.     } elsif ($file =~ /^$re_dev_conf$/) {
  797.         $busid = hex($3);
  798.         $conf = 1 if ($busid eq $WRAP_USB_BUS or $busid eq 0 or
  799.               $busid eq $WRAP_PCI_BUS);
  800.     }
  801.     }
  802.     close(LS2);
  803.     printf DBG "status: $sys, $inf, $conf\n";
  804.     if ($sys eq 0 or $inf eq 0 or $conf eq 0) {
  805.     $ret = "invalid driver!";
  806.     return $ret;
  807.     }
  808.     $ret = "driver installed";
  809.     open(LS2, "ls -1 $confdir/$driver|") or
  810.       die "couldn't open $confdir/$driver: $!";
  811.  
  812.     while (my $file = <LS2>) {
  813.     chomp($file);
  814.     next if ($file !~ /\.conf$/);
  815.     $conf = 0;
  816.     if ($file =~ /^$re_sub_dev_conf$/) {
  817.         ($vendor, $device, $subvendor, $subdevice, $busid) =
  818.           (uc($1), uc($2), uc($3), uc($4), hex($5));
  819.         $conf = 1;
  820.         foreach my $card (@{$cards}) {
  821.         if ($card->{vendor} eq $vendor and
  822.             $card->{device} eq $device and
  823.             $card->{subvendor} eq $subvendor and
  824.             $card->{subdevice} eq $subdevice and
  825.             $busid eq $WRAP_PCI_BUS) {
  826.             $ret .= "\n\tdevice ($vendor:$device" .
  827.               ":$subvendor:$subdevice) present";
  828.             $conf = 2;
  829.             last;
  830.         }
  831.         }
  832.     } elsif ($file =~ /^$re_dev_conf/) {
  833.         ($vendor, $device, $subvendor, $subdevice, $busid) =
  834.           (uc($1), uc($2), "\\*", "\\*", hex($3));
  835.         $conf = 1;
  836.         foreach my $card (@{$cards}) {
  837.         if ($card->{vendor} eq $vendor and
  838.             $card->{device} eq $device and
  839.             ($busid eq $WRAP_USB_BUS or $busid eq 0 or
  840.              $busid eq $WRAP_PCI_BUS)) {
  841.             $ret .= "\n\tdevice ($vendor:$device) present";
  842.             $conf = 2;
  843.             last;
  844.         }
  845.         }
  846.     }
  847.     next if ($conf le 1);
  848.     # find if kernel knows of an alternate driver for this device
  849.     my $devstring;
  850.     if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
  851.         $devstring = sprintf("usb:v%sp%sd", $vendor, $device);
  852.     } elsif ($busid eq $WRAP_PCI_BUS) {
  853.         $devstring = sprintf("pci:v0000%sd0000%ssv", $vendor, $device);
  854.     } else {
  855.         next;
  856.     }
  857.     open(MODPROBE, "modprobe -c|") or next;
  858.     while (my $line = <MODPROBE>) {
  859.         my $alt;
  860.         chomp($line);
  861.         next if $line !~ /$devstring/;
  862.         $alt = (split(' ', $line))[-1];
  863.         chomp($alt);
  864.         if (length($alt) gt 0 and $alt ne "ndiswrapper") {
  865.         $ret .= " (alternate driver: $alt)";
  866.         last;
  867.         }
  868.     }
  869.     close(MODPROBE);
  870.     }
  871.     close(LS2);
  872.     printf DBG "driver: $driver, $ret\n";
  873.     return $ret;
  874. }
  875.  
  876. ## Local Variables: ##
  877. ## cperl-indent-level: 4 ##
  878. ## End: ##
  879.